/**
 * @file bibclient.c
 * @brief Client del progetto biblio
 * @author Marco Luisi
 * Si dichiara che il contenuto di questo file e' in ogni sua parte opera originale dell' autore.
 */
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>

#include "bib.h"
#include "biblio.h"
#include "bibclient.h"
#include "comsock.h"

/** Pattern delle opzioni utente */
char *option_formats[] = OPTION_FORMATS;
/** Campi per il messaggio al server */
char *message_fields[] = MESSAGE_FIELDS;
/**  Messaggio di richiesta da inviare alle biblioteche*/
message_t msg;
/**  Messaggio di risposta dalle biblioteche*/
message_t res;
/**  Array per il controllo della presenza di opzioni multiple*/
static int fields[NCAMPI]; /*Essendo static è inizializzato a 0*/

/**
 * @brief Main del client
 * @param argv Opzioni di lancio del client
 * @return Exit status del programma
 */
int main(int argc,char *argv[]){
	int i;
	int listen = TRUE;
	int con;
	int rcv;
	char bibname[UNIX_PATH_MAX];
	char bibsock[UNIX_PATH_MAX];
	FILE* conf;

	/* Controllo dei parametri di avvio del client */
	if((argc < 2) | (argc > (NCAMPI + 2)) ){
		fprintf(stderr,ERR_PARAM);
		return(EXIT_FAILURE);
	}
	msg.type = MSG_QUERY;
	msg.length = 0;

	/* Parsing dei parametri di avvio */
	for(i = 1; i < argc; i++){
		switch(parse_option(argv[i])){
		case(PARSE_ERROR):{
			fprintf(stderr, ERR_OPT,argv[i]);
			exit(EXIT_FAILURE);
			break;
		}

		case(PARSE_MUL):{
			fprintf(stderr, ERR_MUL,argv[i]);
			exit(EXIT_FAILURE);
			break;
		}

		case(PARSE_MAXBUF):{
			fprintf(stderr, ERR_BUF);
			exit(EXIT_FAILURE);
			break;
		}

		case(PARSE_OK):{
			break;
		}

		}

	}
	/* Richieste dell'utente impostate, si legge il file di configurazione per comunicare con le biblioteche */
	conf = fopen(CONF,"r");
	if (conf == NULL){
		fprintf(stderr,ERR_FIL);
		return(EXIT_FAILURE);
	}
	/* Per ogni biblioteca si tenta la connessione e in caso di esito positivo si invia la richiesta dell'utente,attendendo la risposta */
	while(fgets(bibname,UNIX_PATH_MAX,conf) != NULL){
		bibname[strcspn ( bibname, "\n" )] = '\0';
		if(snprintf(bibsock,UNIX_PATH_MAX,"./tmp/%s.sck",bibname) == ERROR){
			fprintf(stderr,ERR_PAT,bibname);
			continue;
		}
		/* In caso di errore di apertura socket o invio si passa alla biblioteca successiva */
		con = openConnection(bibsock,NTRIAL,NSEC);
		if(con == ERROR){
			fprintf(stderr,ERR_CON,bibname);
			continue;
		}
		if(sendMessage(con, &msg) == ERROR){
			fprintf(stderr,ERR_SND,bibname);
			continue;
		}

		/* Ricezione e stampa dei messaggi */
		while(listen == TRUE){
			rcv = receiveMessage(con, &res);
			if(rcv == ERROR && errno != ENOTCONN){
				fprintf(stderr, ERR_COM,bibname);
				if(closeConnection(con) == ERROR){
					fprintf(stderr,ERR_CLS,bibname);
				}
			}
			if(rcv == ERROR && errno == ENOTCONN){
				/* Socket chiusa dal server */
				listen = FALSE;
				printf(BIB_END,bibname);
				continue;
			}
			printf("%s",res.buffer);
		}
		if(closeConnection(con) == ERROR){
			fprintf(stderr,ERR_CLS,bibname);
		}
	}
	return(EXIT_SUCCESS);
}

/**
 * @brief Funzione di parsing dei parametri da riga di comando
 * @param arg argomento da linea di comando da parsare
 * @return risultato del parsing
 * @retval PARSE_ERROR errore
 * @retval PARSE_MAXBUF limite del buffer del messaggio superato
 * @retval PARSE_MUL opzione specificata più volte
 * @retval PARSE_OK opzione corretta
 */
int parse_option(char *arg){
	int i;
	unsigned int len;
	/** Esito di sscanf */
	int parse;
	char s[LLSTRING];
	char m[LLSTRING];
	/* Prima si controlla l'opzione per il prestito */
	if(strcmp(arg,LOAN_) == 0){
		if(msg.type == MSG_LOAN){
			return(PARSE_MUL);
		}
		msg.type = MSG_LOAN;
		return(PARSE_OK);
	}
	/* Poi si controllano tutte le altre possibili opzioni */
	for(i = 0; i < (NCAMPI); i++){
		parse = sscanf(arg,option_formats[i],s);
		if(parse != 1){ /* Si passa all'opzione successiva */
			continue;
		}
		/* Controlla che l'opzione non sia già stata specificata */
		if(fields[i] == 1){
			return(PARSE_MUL);
		}
		sprintf(m,"%s: %s;",message_fields[i],s);
		len = strlen(m);
		msg.length += len;
		if(msg.length > MAXBUF){
			return(PARSE_MAXBUF);
		}
		/* Aggiunge la richiesta formattata al messaggio */
		strcat(msg.buffer,m);
		fields[i] = 1;
		return(PARSE_OK);
	}
	return(PARSE_ERROR);
}
